﻿using MiniFox.Infrastructure.Attributes;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;

namespace MiniFox.Infrastructure
{
    /// <summary>
    /// 
    /// </summary>
    /// <typeparam name="D"></typeparam>
    public class TreeResultObject<D> : TreeResultObjectBase<D>
    {
        IEnumerable<D> _flatData;
        /// <summary>
        /// 
        /// </summary>
        /// <param name="flatData"></param>
        public TreeResultObject(IEnumerable<D> flatData) : base(flatData.Count())
        {
            _flatData = flatData;
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="flatData"></param>
        /// <param name="nodeKey"></param>
        /// <param name="superKey"></param>
        /// <param name="sortKey"></param>
        /// <param name="groupKey"></param>
        public TreeResultObject(IEnumerable<D> flatData, string nodeKey, string superKey, string sortKey, string groupKey)
            : base(flatData.Count(), nodeKey, superKey, sortKey, groupKey)
        {
            _flatData = flatData;
        }
        /// <summary>
        /// 扁平化原始数据(自关联数据)
        /// </summary>
        protected IEnumerable<D> FlatData
        {
            get
            {
                return _flatData;
            }
        }
        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        protected override IEnumerable<IGrouping<object, D>> GetGroups()
        {
            var genericType = typeof(D);
            ParameterExpression parameterExp = Expression.Parameter(genericType);
            var groupProperty = parameterExp.Type.GetProperty(GroupKey, BindingFlags.Public | BindingFlags.Instance | BindingFlags.IgnoreCase);
            var propertyExpression = Expression.PropertyOrField(parameterExp, groupProperty.Name);
            var groupExpression = Expression.Lambda<Func<D, object>>(propertyExpression, parameterExp);
            var groups = FlatData.GroupBy(groupExpression.Compile());
            return groups;
        }
    }
    /// <summary>
    /// 
    /// </summary>
    /// <typeparam name="D"></typeparam>
    /// <typeparam name="T"></typeparam>
    public class TreeResultObject<D, T> : TreeResultObject<D>
    {
        Func<D, T> _mappingFunc;

        /// <summary>
        /// 
        /// </summary>
        /// <param name="flatData"></param>
        /// <param name="mappingNodeData"></param>
        /// <exception cref="ArgumentNullException"></exception>
        public TreeResultObject(IEnumerable<D> flatData, Func<D, T> mappingNodeData)
            : base(flatData)
        {
            if (mappingNodeData == null)
                throw new ArgumentNullException("mappingNodeData");
            _mappingFunc = mappingNodeData;
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="flatData"></param>
        /// <param name="uniqueKey"></param>
        /// <param name="superKey"></param>
        /// <param name="sortKey"></param>
        /// <param name="groupKey"></param>
        /// <param name="mappingNodeData"></param>
        /// <exception cref="ArgumentNullException"></exception>
        public TreeResultObject(IEnumerable<D> flatData, string uniqueKey, string superKey, string sortKey, string groupKey, Func<D, T> mappingNodeData)
            : base(flatData, uniqueKey, superKey, sortKey, groupKey)
        {
            if (mappingNodeData == null)
                throw new ArgumentNullException("mappingNodeData");
            _mappingFunc = mappingNodeData;
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="groupId"></param>
        /// <param name="groupFlatData"></param>
        /// <returns></returns>
        protected override ITreeGroup CreateTreeGroup(object groupId, IEnumerable<D> groupFlatData)
        {
            return new TreeGroup<D, T>(groupId, this.NodeKey, this.SuperKey, this.SortKey, groupFlatData, this._mappingFunc);
        }
    }
}
